﻿using System;
using FibMatrix.Schedule;
using UnityEngine;
using UObject = UnityEngine.Object;

namespace FibMatrix
{
    [FM_Mono.IgnoreGen]
    public class DefaultUAssetLoadHandle : IUAssetLoadHandle
    {
        public DefaultUAssetLoadHandle(UObject asset)
        {
            this._asset = asset;
            this.isCompleted = true;
        }

        public DefaultUAssetLoadHandle(ResourceRequest assetRequest)
        {
            this._assetRequest = assetRequest;
            if (this._assetRequest.isDone)
            {
                this._asset = this._assetRequest.asset;
                this._assetRequest = null;
                this.isCompleted = true;
            }
            else
            {
                this._assetRequest.completed += this.OnAsyncAssetComplete;
                this.isCompleted = false;
                // this._loopQueryHandler = GlobalScheduler.AddFrameLimitUpdator(1, LoopQueryAssetStatus, this);
            }
        }

        private UObject _asset;
        private ResourceRequest _assetRequest;
        private int _delayDispatchHandler;

        public UObject asset
        {
            get
            {
                if (this._asset == null && _assetRequest != null)
                {
                    this._assetRequest.completed -= this.OnAsyncAssetComplete;
                    this.ApplyAsset(this._assetRequest.asset, true);
                }
                return this._asset;
            }
        }

        public bool isCompleted
        {
            get;
            private set;
        }

        public bool Unload()
        {
            if (this._assetRequest != null)
            {
                this._assetRequest.completed -= this.OnAsyncAssetComplete;
                this._assetRequest = null;
            }
            bool needUnloadUnusedAsset = false;
            this._completeCallback = null;
            var obj = this.asset;
            if (obj)
            {
                if (!(obj is GameObject))
                {
                    Resources.UnloadAsset(obj);
                }
                else
                {
                    needUnloadUnusedAsset = true;
                }
            }
            this._asset = null;
            GlobalScheduler.RemoveLimitUpdator(ref this._delayDispatchHandler);
            return needUnloadUnusedAsset;
        }

        private Action<IAsyncBase> _completeCallback;

        public event Action<IAsyncBase> completeCallback
        {
            add
            {
                this._completeCallback += value;
            }

            remove
            {
                this._completeCallback -= value;
            }
        }

        private void OnAsyncAssetComplete(AsyncOperation op)
        {
            op.completed -= this.OnAsyncAssetComplete;
            if (this._assetRequest != op)
            {
                return;
            }
            var request = op as ResourceRequest;
            if (request != null && request.isDone)
            {
                this.ApplyAsset(request.asset, false);
            }
        }

        private void ApplyAsset(UObject asset, bool delayDispatch)
        {
            // if (this._loopQueryHandler != null)
            // {
            //     GlobalScheduler.RemoveLimitUpdator(this._loopQueryHandler);
            //     this._loopQueryHandler = null;
            // }
            this._assetRequest = null;
            this._asset = asset;
            this.isCompleted = true;

            if (!delayDispatch)
            {
                this.DispatchCompleteEvent(null);
            }
            else if (!GlobalScheduler.IsValid(this._delayDispatchHandler))
            {
                this._delayDispatchHandler = GlobalScheduler.CallOnceFrame(1, this.DispatchCompleteEvent);
            }
        }

        private void DispatchCompleteEvent(object context)
        {
            this._delayDispatchHandler = -1;
            Action<IAsyncBase> callback = this._completeCallback;
            this._completeCallback = null;
            if (callback != null)
            {
                callback(this);
            }
        }
    }
}
